/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sg.edu.nus.iss.pacman.midlet;

import java.util.Vector;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;

import sg.edu.nus.iss.pacman.dao.Maze;
import sg.edu.nus.iss.pacman.dao.Score;
import sg.edu.nus.iss.pacman.dao.TopScoreUser;
import sg.edu.nus.iss.pacman.dao.UserProfile;
import sg.edu.nus.iss.pacman.form.DownloadMazeForm;
import sg.edu.nus.iss.pacman.form.DownloadMazeList;
import sg.edu.nus.iss.pacman.form.EnterUserProfileForm;
import sg.edu.nus.iss.pacman.form.MainMenuList;
import sg.edu.nus.iss.pacman.form.MessageInfo;
import sg.edu.nus.iss.pacman.form.NoRemoteDeviceFoundInfo;
import sg.edu.nus.iss.pacman.form.SearchingInProgressInfo;
import sg.edu.nus.iss.pacman.form.SelectDownloadMazeList;
import sg.edu.nus.iss.pacman.form.SelectMazeList;
import sg.edu.nus.iss.pacman.form.SelectRemoteDeviceList;
import sg.edu.nus.iss.pacman.form.SendChallengeChoiceList;
import sg.edu.nus.iss.pacman.form.SendChallengeViaSMSForm;
import sg.edu.nus.iss.pacman.form.UserProfileOptionList;
import sg.edu.nus.iss.pacman.form.UserProfileUploadMessage;
import sg.edu.nus.iss.pacman.form.ViewHighScoreForm;
import sg.edu.nus.iss.pacman.form.ViewHighScoreUserProfile;
import sg.edu.nus.iss.pacman.form.ViewMapHighScore;
import sg.edu.nus.iss.pacman.game.PacManGame;
import sg.edu.nus.iss.pacman.manager.bluetooth.BluetoothClientManager;
import sg.edu.nus.iss.pacman.manager.dao.MazeManager;
import sg.edu.nus.iss.pacman.manager.dao.UserProfileManager;
import sg.edu.nus.iss.pacman.manager.sms.SMSClientManager;
import sg.edu.nus.iss.pacman.manager.webservice.WebServiceClientManager;
import sg.edu.nus.iss.pacman.ui.PacManUI;

/**
 * A MIDlet class for PacManScreen.
 *
 * @author fredy, daniel, daniel martana
 */
public class PacManMIDlet extends MIDlet implements PacManScreen {

    public static final String TITLE = "PacMan Game";
    public static final String LABEL_CMD_BACK = "Back";
    public static final String LABEL_CMD_SELECT = "Select";
    public static final String LABEL_CMD_OK = "OK";
    public static final String LABEL_CMD_CANCEL = "Cancel";
    public static final String LABEL_CMD_SEND = "Send";
    public static final String LABEL_CMD_EXIT = "Exit";
    public static final String LABEL_CMD_TERMINATE = "Terminate";
    private PacManUI pacManUI;
    private SendChallengeChoiceList sendChallengeList;
    private SendChallengeViaSMSForm sendChallengeViaSMSForm;
    private MessageInfo messageInfo;
    private MainMenuList mainMenuList;
    private DownloadMazeList downloadMazeList;
    private SelectDownloadMazeList selectDownloadMazeList;
    private DownloadMazeForm downloadMazeForm;
    private SelectMazeList selectMazeList;
    private SelectRemoteDeviceList selectRemoteDeviceList;
    private BluetoothClientManager bluetoothClientMgr;
    private SearchingInProgressInfo searchingInProgressInfo;
    private UserProfileManager userProfileMgr;
    private String[] listDevices;
    private ViewHighScoreForm viewHighScoreForm;
    private ViewHighScoreUserProfile viewHighScoreUserProfile;
    private EnterUserProfileForm enterUserProfileForm;
    private UserProfileUploadMessage userProfileUploadMessage;
    private MazeManager mazeMgr;
    private SMSClientManager smsClientMgr;
    private ViewMapHighScore viewMapHighScore;
    private NoRemoteDeviceFoundInfo noRmtDvcScreen;
    private Maze selectedMaze;
    private Score scoreResult;
    private WebServiceClientManager webSvcMgr;
    private UserProfile selectedUserProfile;
    private UserProfileOptionList userProfileOptionList;
    private String serverURL;
    
    private String DEFAULT_RMS = "default";

    /**
     * Constructor for MIDlet application
     */
    public PacManMIDlet() {
        sendChallengeViaSMSForm = new SendChallengeViaSMSForm(this);
        sendChallengeList = new SendChallengeChoiceList(this);
        mainMenuList = new MainMenuList(this);
        bluetoothClientMgr = new BluetoothClientManager(this);
        searchingInProgressInfo = new SearchingInProgressInfo(this);
        userProfileMgr = new UserProfileManager();
        userProfileUploadMessage = new UserProfileUploadMessage(this);
        enterUserProfileForm = new EnterUserProfileForm(this);
        userProfileUploadMessage = new UserProfileUploadMessage(this);
        mazeMgr = new MazeManager();
        noRmtDvcScreen = new NoRemoteDeviceFoundInfo(this);
        serverURL = getAppProperty("Server-URL");
        webSvcMgr = new WebServiceClientManager(getServerURL(),this);
     
        //initialize Record Management Store for Maze
        prepareDefaultMap();
    }

    protected void startApp() {
        // Display.getDisplay(this).setCurrent(pacManUI);
        displayMainMenu();
    }

    protected void pauseApp() {
    }

    protected void destroyApp(boolean unconditional) {
        notifyDestroyed();
    }

    // Navigation methods
    /**
     * Quits the application
     */
    public void quit() {
        try {
            destroyApp(false);
        } catch (Exception e) {
            e.printStackTrace();
            displayAlertError(e.getMessage());
        }
    }

    /**
     * Displays Main Menu screen
     */
    public void displayMainMenu() {
        Display.getDisplay(this).setCurrent(mainMenuList);
    }

    /**
     * Display Challenge Message screen
     */
    public void displayChallengeMessage(String message) {
    }

    /**
     * Displays Alert for Error message
     */
    public void displayAlertError(String message) {
        Alert alert = new Alert(TITLE, message, null, AlertType.ERROR);
        Display.getDisplay(this).setCurrent(alert);
    }

    /**
     * Displays Alert for Information message
     */
    public void displayAlertInfo(String message) {
        Alert alert = new Alert(TITLE, message, null, AlertType.INFO);
        Display.getDisplay(this).setCurrent(alert);
    }

    /**
     * Displays Alert for Warning message
     */
    public void displayAlertWarning(String message) {
        Alert alert = new Alert(TITLE, message, null, AlertType.WARNING);
        Display.getDisplay(this).setCurrent(alert);
    }

    /**
     * Displays Confirmation message
     */
    public void displayInfo(String message) {
        messageInfo = new MessageInfo(this, message);
        Display.getDisplay(this).setCurrent(messageInfo);
    }

    /**
     * Displays Send Challenge Choice List screen
     */
    public void displaySendChallengeChoiceList() {
        Display.getDisplay(this).setCurrent(sendChallengeList);
    }

    /**
     * Displays screen for user to enter telephone number
     */
    public void displaySendChallengeViaSMS() {
        Display.getDisplay(this).setCurrent(sendChallengeViaSMSForm);
    }

    /**
     * Displays screen for user to select a remote device
     */
    public void displaySendChallengeViaBluetooth() {
        bluetoothClientMgr.searchRemoteDevices();
        Display.getDisplay(this).setCurrent(searchingInProgressInfo);
    }

    public void listBluetoothDevices(String[] bluetoothDevices) {
        listDevices = bluetoothDevices;

        if (listDevices != null && listDevices.length > 0) {
            selectRemoteDeviceList = new SelectRemoteDeviceList(this, listDevices);
            Display.getDisplay(this).setCurrent(selectRemoteDeviceList);
        } else {
            Display.getDisplay(this).setCurrent(noRmtDvcScreen);
        }
    }

    public void sendChallengeViaSMS(String telpNo) {
        smsClientMgr = new SMSClientManager(this, "+" + telpNo);
        smsClientMgr.sendChallenge();
    }

    public void sendChallengeViaBluetooth(int idxDevice, String rmtDevice) {
        bluetoothClientMgr.setBluetoothDeviceIndex(idxDevice);
        bluetoothClientMgr.sendChallenge();
    }

    /**
     * Launches the game
     *
     * @param maze
     *            Maze
     */
    // public void launchGame(Maze maze) {
    // pacManUI = new PacManUI();
    // Display.getDisplay(this).setCurrent(pacManUI);
    // }
    public void launchGame(Maze maze) {
        this.selectedMaze = maze;
        pacManUI = new PacManUI(this, maze.getMap());
        Display.getDisplay(this).setCurrent(pacManUI);
    }

    /**
     * Displays View Screen List screen
     */
    public void displayHighScoresList(String mazeName) {
        TopScoreUser[] userProfile = userProfileMgr.getListOfTopScorers(mazeName);
        viewHighScoreForm = new ViewHighScoreForm(this, userProfile);
        Display.getDisplay(this).setCurrent(viewHighScoreForm);
    }

    /**
     * Display High Scorer's Profile
     */
    public void displayHighScoreUserProfile(String userName) {
        UserProfile userProfile = userProfileMgr.getUserProfile(userName);
        viewHighScoreUserProfile = new ViewHighScoreUserProfile(this, userProfile);
        Display.getDisplay(this).setCurrent(viewHighScoreUserProfile);
    }

    /**
     * Display Enter User Profile Form
     */
    public void displayEnterUserProfileForm() {
        Display.getDisplay(this).setCurrent(enterUserProfileForm);
    }

    /**
     * Displays Select Maze List screen
     */
    public void displaySelectMazeList() {
        Maze[] maze = mazeMgr.getMaze();
        
        if (maze == null || maze.length == 0) {
        	displayDownloadedMazeList();
        } else {
        	selectMazeList = new SelectMazeList(this, maze);
            Display.getDisplay(this).setCurrent(selectMazeList);	
        }
    }

    public void displayDownloadedMazeList() {
        downloadMazeList = new DownloadMazeList(this);
        Display.getDisplay(this).setCurrent(downloadMazeList);
    }

    public void displayDownloadMazeForm(String maze) {
        downloadMazeForm = new DownloadMazeForm(this, maze);
        Display.getDisplay(this).setCurrent(downloadMazeForm);
    }

    /**
     * Downloads mazes from server
     */
    public void downloadMaze() {
        // TODO : invoke download Maze manager
        displayInfo("New mazes have already been donwloaded");
    }

    /**
     * Displays Searching In Progress Info screen
     */
    public void displaySearchingInProgressInfo() {
        Display.getDisplay(this).setCurrent(searchingInProgressInfo);
    }

    public void completeGame(int score) {
        // TODO Auto-generated method stub
        scoreResult = new Score();
        scoreResult.setMapName(selectedMaze.getMazeName());
        scoreResult.setScore(score);
    }

    public void displayUserProfile()
    {
        UserProfile[] userProfile = userProfileMgr.getListUserProfiles();
        userProfileOptionList = new UserProfileOptionList(this, userProfile, scoreResult);
        Display.getDisplay(this).setCurrent(userProfileOptionList);
    }

    public void displayViewMapHighScore() {
        Maze[] maze = mazeMgr.getMaze();
        viewMapHighScore = new ViewMapHighScore(this, maze);
		Display.getDisplay(this).setCurrent(viewMapHighScore);
	}
	
	/**
	 * Saves scores into local device database
	 * @param userProfile user profile
	 */
	public void saveScore(UserProfile userProfile) {
        boolean higher = false;
		Vector listScores = userProfile.getScores();
		if (listScores == null || listScores.size() == 0) {
            higher = true;
			listScores = new Vector();
			listScores.addElement(scoreResult);
			userProfile.setScores(listScores);
		} else  {
			for (int i=0; i<listScores.size(); i++) {
				Score userScore = (Score) listScores.elementAt(i);
				
				if (userScore.getMapName().equals(selectedMaze.getMazeName())) {
					int prevScore = userScore.getScore();
					int currScore = scoreResult.getScore();
					
					if (prevScore < currScore) {
                        higher = true;
						userScore.setScore(currScore);
					} 
				} else if (i == (listScores.size() - 1)) {
					listScores.addElement(scoreResult);
				}
			}
		}
		
		userProfileMgr.saveUserProfile(userProfile);
		selectedUserProfile = userProfile;
        if (higher) // Show upload user profile only if the score is higher.
        {
            Display.getDisplay(this).setCurrent(userProfileUploadMessage);
        }
        else
        {
            displayMainMenu();
        }
    }

    /**
     * Terminates Remote device searching process
     */
    public void terminateRemoteDeviceSearching() {
        bluetoothClientMgr.cancelSearchRemoteDevices();
        displaySendChallengeChoiceList();
    }

    public void displayDownloadedMazeList(String[] mazeList) {
        selectDownloadMazeList = new SelectDownloadMazeList(this, mazeList);
        Display.getDisplay(this).setCurrent(selectDownloadMazeList);
    }
    
    /**
     * Uploads user profile to server
     */
    public void uploadUserProfile() {
    	webSvcMgr.uploadUserProfile(selectedUserProfile);
    	displayMainMenu();
    }

    /**
     * Gets the server URL.
     * @return the serverURL the server URL
     */
    public String getServerURL()
    {
        return serverURL;
    }
    
    private void prepareDefaultMap() {
    	//Check whether the RMS doesn't have any maze
    	Maze[] listMaze = mazeMgr.getMaze();
    	boolean flag = true;
    	
    	if (listMaze != null && listMaze.length > 0) {
    		for (int i=0; i<listMaze.length; i++) {
    			Maze maze = listMaze[i];
    			
    			if (maze.getMazeName().equals(DEFAULT_RMS)) {
    				flag = false;
    				break;
    			}
    		}
    	}
    	
    	if (flag) {
    		Maze maze = new Maze();
    		maze.setMazeName("default");
    		maze.setMap(PacManGame.DEFAULT_MAZE);
    		mazeMgr.saveMaze(maze);
    	}
    }
}
